package cn.com.dhcc.app.pub.core.util;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.log4j.Logger;

import cn.com.dhcc.app.core.service.Log;
import cn.com.dhcc.app.core.service.Log.LOGTYPE;
import cn.com.dhcc.app.core.util.Status;

/**
 * Created by zss on 2014/5/16.
 */
public class FtpUtil {
	@SuppressWarnings("deprecation")
	private static Logger  logger = Log.getDetachLogger(LOGTYPE.FTP);

    public static boolean login(FTPClient ftp, String host, String username, String password, int port) throws IOException {
        //添加监听器
        ftp.setDefaultTimeout(20000);
        ftp.setConnectTimeout(20000);  //设置连接超时时间。10秒
        ftp.setDataTimeout(20000);      //设置数据超时   10秒
        ftp.setBufferSize(1024*1024*10);
        ftp.setControlKeepAliveTimeout(30000);
        ftp.setDefaultPort(port);
        ftp.setControlEncoding("utf-8");
        logger.info("开始连接ftp服务器====="+host+"===>");
        //登陆
        ftp.connect(host);
        logger.info("连接ftp服务器成功===="+host+"====>");
        int code = ftp.getReplyCode();//获取响应码
        logger.error("连接ftp服务器成功===="+host+"====响应码"+code+">");
        if (!FTPReply.isPositiveCompletion(code)) {
            logger.error("拒绝连接，错误代码=" + code + ",返回消息：" + ftp.getReplyString());
            ftp.disconnect();
            return false;
        }
        ftp.login(username, password);
        logger.error("FTP登陆返回消息："+ftp.getReplyString());
        code = ftp.getReplyCode();
        if (!FTPReply.isPositiveCompletion(code)) {
            logger.error("登陆失败，错误代码=" + code + ",返回消息：" + ftp.getReplyString());
            ftp.disconnect();
            return false;
        }
        ftp.setFileType(FTPClient.BINARY_FILE_TYPE);//设置文件的传输方式。
        ftp.setSoTimeout(60000);
        ftp.setKeepAlive(false);
        return true;
    }

    public static Status upload(FTPClient ftpClient,String host, String username, String password, int port, File fromfile, String tofilename) {
    	logger.info("进入方法upload,上传文件【"+tofilename+"】开始.....");
    	tofilename = tofilename.replace("\\", "/");
        Status status = Status.getInstance();
        try {
            boolean b = login(ftpClient, host, username, password, port);
            if (!b) {
                status.setSuccess(false);
                status.setMsg("登陆FTP服务器失败,host=" + host + ",username=" + username + ",password=" + password);
                return status;
            }
            b = upload(ftpClient, fromfile, tofilename);
            if (b) {
                status.setSuccess(true);
                status.setMsg("上传成功tofilename=" + tofilename + ",fromfile=" + fromfile.getParent() + "/" + fromfile.getName());
                return status;
            } else {
                status.setSuccess(false);
                status.setMsg("上传文件失败tofilename=" + tofilename + ",fromfile=" + fromfile.getParent() + "/" + fromfile.getName());
                return status;
            }
            
        } catch (IOException e) {
            status.setSuccess(false);
            status.setMsg("上传文件失败,原因：" + e.getMessage());
            logger.error("上传文件【"+tofilename+"】失败....."+e);
            return status;
        } finally {
        	logger.info("上传文件【"+tofilename+"】完成关闭ftp连接.....");
            logout(ftpClient);
        }
    }

    public static Status upload(FTPClient ftpClient,String host, String username, String password, int port, String fromxml, String tofilename) {
        
    	logger.info("上传xml文件开始....."+tofilename);
    	tofilename = tofilename.replace("\\", "/");
        Status status = Status.getInstance();
        try {
            boolean b = login(ftpClient, host, username, password, port);
            logger.info("上传xml文件登陆成功....."+tofilename);
            if (!b) {
                status.setSuccess(false);
                status.setMsg("登陆FTP服务器失败,host=" + host + ",username=" + username + ",password=" + password);
                return status;
            }
            
            b = upload(ftpClient, fromxml, tofilename);
            if (b) {
            	logger.info("上传xml文件成功....."+tofilename);
                status.setSuccess(true);
                status.setMsg("上传成功");
                return status;
            } else {
            	logger.info("上传xml文件失败....."+tofilename);
                status.setSuccess(false);
                status.setMsg("上传文件失败");
                return status;
            }

        } catch (IOException e) {
            status.setSuccess(false);
            status.setMsg("上传文件失败,原因：" + e.getMessage());
            logger.info("上传xml文件失败....."+tofilename+e);
            return status;
        } finally {
        	logger.info("上传xml文件退出....."+tofilename);
            logout(ftpClient);
        }
    }

    private static boolean upload(FTPClient ftp, String xml, String tempfilename) throws IOException {
        int j = tempfilename.lastIndexOf("/");
        String filename = tempfilename.substring(j + 1);
        if (j >= 0) {
            String ftpdir = tempfilename.substring(0, j);
        	ftp.enterLocalPassiveMode();
            ftp.changeWorkingDirectory(ftpdir);
            int code = ftp.getReplyCode();
            if (FTPReply.isNegativePermanent(code)) {
                //如果文件不存在。创建文件夹。
                boolean b = createDirecroty(ftpdir, ftp);
                if (b) {
                    logger.info("[FtpUtil.upload(ftp, xml, tempfilename)]创建文件夹" + ftpdir + "成功。");
                    ftp.enterLocalPassiveMode();
                    ftp.changeWorkingDirectory(ftpdir);//切换到文件夹
                } else {
                    logger.warn("[FtpUtil.upload(ftp, xml, tempfilename)]创建文件夹" + ftpdir + "失败。退出文件上传" + filename);
                    return false;
                }
            }
        }
        //没有做断点续传
        InputStream inputStream = new ByteArrayInputStream(xml.getBytes("utf-8"));
    	ftp.enterLocalPassiveMode();
        boolean b = ftp.storeFile(filename + ".tmp", inputStream);
        inputStream.close();
        if (b) {
        	logger.info("[FtpUtil.upload(ftp, xml, tempfilename)]写入文件" + filename + "成功，更改服务器文件。");
            return replacetemp(ftp, filename + ".tmp", filename);
        }else{
        	return false;
        }
    }

    private static boolean upload(FTPClient ftp, File localfile, String tempfilename) throws IOException {
        int j = tempfilename.lastIndexOf("/");
        String filename = tempfilename.substring(j + 1);
        if (j >= 0) {
            String ftpdir = tempfilename.substring(0, j);
            ftp.enterLocalPassiveMode();
            ftp.changeWorkingDirectory(ftpdir);
            int code = ftp.getReplyCode();
            if (FTPReply.isNegativePermanent(code)) {
            	ftp.enterLocalPassiveMode();
                //如果文件不存在。创建文件夹。
                boolean b = createDirecroty(ftpdir, ftp);
                if (b) {
                    logger.info("[FtpUtil.upload(ftp, localfile, tempfilename)]创建文件夹" + ftpdir + "成功。");
                    ftp.enterLocalPassiveMode();
                    ftp.changeWorkingDirectory(ftpdir);//切换到文件夹
                } else {
                    logger.warn("[FtpUtil.upload(ftp, localfile, tempfilename)]创建文件夹" + ftpdir + "失败。退出文件上传" + filename);
                    return false;
                }
            }
        }

        //没有做断点续传
        System.out.println(Thread.currentThread().getId()+"--"+"开始上传");
        FileInputStream inputStream = new FileInputStream(localfile);
        ftp.enterLocalPassiveMode();
        boolean b = ftp.storeFile(filename + ".tmp", inputStream);
        System.out.println(Thread.currentThread().getId()+"--"+"上传结束");
        inputStream.close();
        if (b) {
        	logger.info("[FtpUtil.upload(ftp, localfile, tempfilename)]写入文件" + filename + "成功，更改服务器文件。");
            return replacetemp(ftp, filename + ".tmp", filename);
        }else{
        	return false;
        }
        
    }
    /** */
    /**
     * 递归创建远程服务器目录
     *
     * @param ftpdir    远程服务器文件绝对路径
     * @param ftpClient FTPClient对象
     * @return 目录创建是否成功
     * @throws IOException
     */
    private static boolean createDirecroty(String ftpdir, FTPClient ftpClient) throws IOException {
    	ftpClient.enterLocalPassiveMode();
    	ftpClient.changeWorkingDirectory("/");//先切换到根目录
        if (!ftpClient.changeWorkingDirectory(new String(ftpdir.getBytes("utf-8"), "iso-8859-1"))) {
            //如果远程目录不存在，则递归创建远程服务器目录
            int start = 0;
            int end = 0;
            if (ftpdir.startsWith("/")) {
                start = 1;
            } else {
                start = 0;
            }
            end = ftpdir.indexOf("/", start);
            while (true) {
                if (end <= start) {
                    if (start < ftpdir.length()) {
                        end = ftpdir.length();
                    } else {
                        break;
                    }

                }
                String subDirectory = new String(ftpdir.substring(start, end).getBytes("utf-8"), "iso-8859-1");
                ftpClient.enterLocalPassiveMode();
                if (!ftpClient.changeWorkingDirectory(subDirectory)) {
                	ftpClient.enterLocalPassiveMode();
                    if (ftpClient.makeDirectory(subDirectory)) {
                    	ftpClient.enterLocalPassiveMode();
                        ftpClient.changeWorkingDirectory(subDirectory);
                    } else {
                        return false;
                    }
                }
                start = end + 1;
                end = ftpdir.indexOf("/", start);
                //检查所有目录是否创建完毕
            }
        }
        return true;
    }

    public static void logout(FTPClient ftpClient) {
        if (ftpClient.isConnected()) {
        	logger.info("断开与服务器的连接。");
            try {
            	ftpClient.quit();
                ftpClient.disconnect();
                ftpClient = null;
            } catch (IOException e) {
               
            }
        }

    }

    private static boolean replacetemp(FTPClient ftpClient, String tempfilename, String filename) throws IOException {
    	ftpClient.enterLocalPassiveMode();
        FTPFile[] files = ftpClient.listFiles(filename);
        if (files.length == 1) { //说明原文件存在。
        	ftpClient.enterLocalPassiveMode();
            boolean b = ftpClient.deleteFile(filename);
            if (b) {
                logger.info("源文件存在，删除服务器原文件成功:" + filename);
            } else {
                logger.warn("源文件存在，删除服务器原文件失败======但由于程序需要，还是要尝试一下重命名========" + filename);
               // return false;
            }
        }
        ftpClient.enterLocalPassiveMode();
        logger.info(Thread.currentThread().getId()+"--"+"开始重命名");
        boolean b = ftpClient.rename(tempfilename, filename);
        logger.info(Thread.currentThread().getId()+"--"+"重命名结束"+b);
        if (b) {
            logger.info("更改服务器文件成功，更改后的文件名是：" + tempfilename + "--->>>" + filename);
        } else {
            logger.warn("更改服务器文件名失败--->>>文件名：" + tempfilename + "，本文件上传退出");
            return false;
        }
        return true;
    }
    
    
    //下载文件的底层方法
    public static boolean download(FTPClient ftp, FTPFile ftpFile, String localroot, String ftppath) throws IOException {
        String ftpFilename = ftpFile.getName();
        File dir = new File(localroot, ftppath);
        boolean b = true;
        if (!dir.exists()) {
            b = dir.mkdirs();
        }
        if (!b) {
            return false;
        }
        File localfiletmp = new File(dir, ftpFilename + ".tmp");     //创建本地文件.
        logger.info("开始接收文件：" + localfiletmp.getName());
        FileOutputStream out = new FileOutputStream(localfiletmp);
        b = ftp.retrieveFile(ftpFilename, out);
        out.flush();
        out.close();
        if (localfiletmp.length() <= 0) {
            b = false;//0字节文件无效.
            localfiletmp.delete();//删除该文件.
            logger.info(localfiletmp + "文件无效，删除。");
        }
        if (b) {
            File localfile = new File(dir, ftpFilename);
            if (localfile.exists()) {
                //删除文件，
            	logger.info(localfile + "已存在，删除。");
                localfile.delete();
            }
            //重命名tmp文件
            localfiletmp.renameTo(new File(dir, ftpFilename));
            logger.info("重命名文件：" + ftpFilename);
        }
        return b;
    }
}
